import re
import httplib
import beerInfo
from sqloader import sqlloader
import sys,os

mainUrl = r'''www.thebeerstore.ca''' #: root url of the beerstore
mainPath = r'''/Beers/''' #: path where beer information is stored 
connection = None #: holds the active connection to the beerstore website
beers = [] #: list of beer objects that contain info on a single beer

def parseBeers(path):
	''' Read in the list of beers and parse information for each one.
	Parse the output of
	http://www.thebeerstore.ca/Beers/brandsearch_results.asp?brand=&beertype=-
	+All+-&category=-+All+-&producer=-+All+-&Submit.x=52&Submit.y=19&
	Submit=Submit

	which contains all the known beers. This output has been curled before hand
	for efficiency.
	
	@param path: location where the sqlite3 database of parsed beers 
	will be created.
	@type path: string
	
	'''

	f = open('out.html', 'r')

	#contents
	contents = f.read()

	#section regex
	premiumStr = r"""<b>Premium Brands.*?</b>(?P<contents>.*?)<b>Imported Brands.*?</b>"""
	premium = re.compile(premiumStr, re.DOTALL)

	importStr = r"""<b>Imported Brands.*?</b>(?P<contents>.*?)<b>Discount Brands.*?</b>"""
	importC = re.compile(importStr, re.DOTALL)

	discountStr = r"""<b>Discount Brands.*?</b>(?P<contents>.*)"""
	discount = re.compile(discountStr, re.DOTALL)

	#link regex
	lStr = r"""<a href='(?P<link>.*?)'.*?<b>(?P<name>.*?)</b></a>"""
	link = re.compile(lStr, re.DOTALL)

	#begin parsing
	premiumContents = premium.search(contents).group(1)
	importContents = importC.search(contents).group(1)
	discountContents = discount.search(contents).group(1)

	sloader = sqlloader(path)
	sloader.setupBeerDatabase()
							
	parseSection(premiumContents,link, 'premium',sloader)
	parseSection(importContents, link, 'import', sloader)
	parseSection(discountContents, link, 'discount', sloader)
			
	sloader.close()
	#dumpBeers()
	
	f.close()

def parseSection(contents,linkregex,category,sloader):
	'''
	Parse a section (premium,import, or discount) and return the beers.

	@type contents: string
	@param contents: html of the given section

	@type linkregex: compiled regex
	@param linkregex: see parseBeers() for the regex string

	@type category: string
	@param category: the section category. premium, import, budget etc.
	
	@type sloader: sqlloader object
	@param sloader: object for writing parsed data to the sql database 
	'''

	global beers
			
	count = 0
	print 'Number of beers read for this section (' + category + ') :...'
	for result in linkregex.finditer(contents):
		pLink = result.group('link')
		pName = result.group('name')
		brandInfo = parseBrandSplash(pLink)
		prices = parsePriceList(brandInfo[4]) #parse the returned pricelist url
		beer = beerInfo.Beer((pName,) + brandInfo,prices, category)
		#beers.append(beer)
		sloader.addBeer(beer)
		sloader.addPricing(beer)
		count = count + 1
		print `count` + "... " + pName
		#if count == 1: break
		
	print count	


def parseBrandSplash(link):
	'''Retrieve the link where prices exist from a beer brand's splash page and
	parse beer information.
	
	@type link: string
	@param link: brand id link i.e branddetails.asp?id=0151

	@rtype: tuple
	@returns: tuple of (brewer,alcohol level,beer type, description, price link)
	@raise AttributeError: if no valid information was found.

	'''
	
	contents = openUrl(link)
	
	#brewer regex
	brewStr = r"""<b>Brewer:</b>(?P<brewer>.*?)<br>"""
	brewer = (re.compile(brewStr,re.DOTALL)).search(contents).group(1)
	brewer = stripWhiteSpace(brewer)

	#alcohol content regex
	alcoholStr = r"""<b>Alcohol Content:</b>(.*?)<br>"""
	alcohol = (re.compile(alcoholStr,re.DOTALL)).search(contents).group(1)
	alcohol = stripWhiteSpace(alcohol)
	alcohol = alcohol[:-1] #strip '%' character from percentage.
	
	#type of beer regex
	beerStr = r"""<b>Type of Beer: </b>(?P<beerType>.*?)<p>(?P<description>.*?)</font>"""
	beerRegex = re.compile(beerStr, re.DOTALL)

	beerType = beerRegex.search(contents).group('beerType')
	beerType = stripWhiteSpace(beerType)

	beerDescription = beerRegex.search(contents).group('description')
	beerDescription = beerDescription.lstrip()
	beerDescription = beerDescription.rstrip()
	beerDescription = stripWhiteSpace(beerDescription)

	#price link regex
	priceLinkStr = r"""<a href="(?P<priceLink>pricelist.asp.*?)".*?>Click here to see a price list for this product</a>"""
	priceLink = re.compile(priceLinkStr,re.DOTALL)

	prefix = priceLink.search(contents).group(1)

	return (brewer,alcohol,beerType,beerDescription,prefix)

def parsePriceList(location):
	'''
	Return the parsed values (quanity,price,locationURL) of the price list table

	@type location: string
	@param location: URL string to open 
	i.e pricelist.asp?str=&id=1710&brandname=NIAGARAS+BEST+BLONDE+PREM+ALE
	
	@rtype: tuple
	@returns: tuple with first element as a list of 3-tuples
	(quantity,price,locationURL) and second element a string representing the
	URL for the "All Packages Sizes".

	'''

	contents = openUrl(location)

	#parse the price table.
	pTableEntry = r"""<TD>(?P<quantity>.*?)</TD>.*?<B>(?P<price>.*?)</B></TD>"""
	pTableStoreLocation = r"""<a href="(../ourstores/stores.asp?.*?)">"""
	pTableAllSizesLocation = r"""All Package Sizes.*?<a href="(.*?)">"""

	entries = re.compile(pTableEntry,re.DOTALL)
	locations = re.compile(pTableStoreLocation,re.DOTALL)

	#Get the offered volume sizes and their prices.
	volumeList = []
	for result in entries.finditer(contents):
		match = (result.group(1),result.group(2))
		volumeList.append(match)

	#Get their corresponding locations.
	locationList = []
	for result in locations.finditer(contents):
		locationList.append(result.group(1))

	#Now combine the two
	retval = []
	for i in range(len(volumeList)):
		retval.append(volumeList[i] + (locationList[i],))

	allLocations = re.compile(pTableAllSizesLocation).search(contents)
	if(allLocations != None): #all locations link may not be included.
		allLocations = allLocations.group(1)

	return retval,allLocations


def openUrl(location):
	'''Retrieve the contents of the URL 'location'
	
	Open and return the html contained at the location 
	starting at mainUrl + mainPath.

	@type location: string
	@param location: url to open

	@rtype: string
	@returns: the html contained at the param, 'location'

	'''

	#if a connection has never been made before make one.
	global connection
	
	if connection == None:
		connection = httplib.HTTPConnection(mainUrl)


	connection.request("GET", mainPath + location)
	response = connection.getresponse()

	status = response.status
	if  status != 200:
		print """Could not retrieve Url:""" + location
		print status
		cleanup()
		exit()

	return response.read()

def stripWhiteSpace(string):
	'''
	Strip left and right whitespace from the input string

	@type string: string
	@param string: string to strip whitespace from

	'''
	string = string.lstrip()
	string = string.rstrip()

	return string

def dumpBeers():
	'''
	Displays all beer info to stdout

	'''

	for beer in beers:
		beer.dumpSelf()

def dumpTotalInfo(brandInfo,pricing):
	'''
	Output a single parsed beer to stdout.

	@type brandInfo: 6-tuple
	@param brandInfo: (beer name, brewer,alcohol level, type, description,
	price link)

	@type pricing: tuple
	@param pricing: (list of 3-tuple -> (quanitity of beer, price,
	buying location), and allSizes location link)

	'''

	name,brewer,alcohol,type,description,link = brandInfo
	pricingList,allStores = pricing

	print name
	print brewer,alcohol,type
	print description
	print link

	for quantity,price,location in pricingList:
		print quantity,price,location

	print allStores

def dumpPriceList(priceTable):
	'''
	Dump a parsed price table to stdout

	@type priceTable: list of tuples
	@param priceTable: points to a list of 3-tuples (quantity,price,locationURL)

	'''

	print 'Found this many items: ' + `len(priceTable[0])`
	for item in priceTable[0]:
		print item

	print priceTable[1]

def dumpBrandInfo(brandInfo):
	'''
	Dump brand information to stdout

	@type brandInfo: 6-tuple
	@param brandInfo: contains (name, brewer,alcohol level, type of beer,
	 description,pricelink)

	'''

	for infoBit in brandInfo:
		print infoBit

def cleanup():
	'''Stops execution and closes up the active connection if any.'''

	if connection != None:
		connection.close()
	
	exit()

def parsePath(filepath):
	'''Check that database path the user wants to use  is legit.
	Check that the user has the proper permissions to write/create
	the desired database and that the path supplied is valid.
	
	@type filepath: string
	@param filepath: the path to the sqlite3 database the user wants to save
	the	parsed information to.
	'''
	
	filepath = filepath.strip()
	if filepath == '':
		print 'Usage: beerparse database_save_location'
		exit()
		
	dirname = os.path.dirname(filepath)
		
	if dirname != '' and not os.path.exists(dirname):
		print 'invalid path specified'
		exit()
	
	if os.path.isdir(filepath):
		print 'path pointed to a directory, invalid path.'
		exit()
	
	if os.path.isfile(filepath):
		if not os.access(filepath, os.W_OK):
			print 'cannot write to path (insufficient permissions)'
			exit()
		else: 
			return
	
	if dirname == '': dirname = '.'
	if not os.access(dirname,os.W_OK):
		print 'insufficient permissions to create file in supplied path' +\
		' ' + dirname
		exit()
		
#def main():
	
#	print "starting run"
#	sloader = sqlloader.sqlloader()
#	sloader.createMainTable()
#	
#	brandInfo = parseBrandSplash('branddetails.asp?id=0604')
#	prices = parsePriceList('pricelist.asp?str=&id=0604&brandname=CANADIAN+67')
#	beer = beerInfo.Beer(('Canadian 67',) + brandInfo,prices,'premium')
#	sloader.addBeer(beer)
#	sloader.addPricing(beer)
#	sloader.dumpTable()
#	sloader.close()
#	print "ending run"
	
#	parseBeers()
	#parseBrandSplash(None,None)
	#dumpPriceList(parsePriceList())

if __name__ == "__main__":
	usage = 'Usage: beerparse database_save_location'
	if len(sys.argv) != 2:
		print usage
		exit()
	parsePath(sys.argv[1])
	parseBeers(sys.argv[1])
